/*
 * @Author: sonss
 * @Date: 2024-08-28 13:43:07
 * @LastEditTime: 2024-08-30 04:13:45
 * @FilePath: /ss-file-antd/src/components/Utils/DownZipButton.tsx
 * @Description:  批量ZIP下载文件
 */
import { DownloadOutlined, LoadingOutlined } from '@ant-design/icons';
import { Button, ButtonProps, Space, Tooltip } from 'antd';
import { saveAs } from 'file-saver';
import JSZip from 'jszip';
import path from 'path';
import { ReactNode, useEffect, useState } from 'react';

type DownZipButtonFile = {
  url: string;
  name?: string;
};

type DownZipButtonProps = ButtonProps & {
  files: DownZipButtonFile[];
  children?: ReactNode;
  zipName?: string;
  onSuccess?: () => void;
  onCancel?: () => void;
  onError?: (err?: any) => void;
};

const DownZipButton: React.FC<DownZipButtonProps> = (props) => {
  const [loading, setLoading] = useState<boolean>();
  const [control, setControl] = useState<AbortController>();
  const [visibleTips, setVisibleTips] = useState<boolean>(false);
  const { files, children, zipName, onSuccess, onCancel, onError, ...rests } = props;

  useEffect(() => {
    setVisibleTips(false);
    if (files.length >= 10) {
      setVisibleTips(true);
      setTimeout(() => setVisibleTips(false), 5000);
    }
  }, [files]);

  const abort = () => {
    control?.abort();
    setControl(undefined);
  };

  const handleDownLoad = async () => {
    const control = new AbortController();
    setControl(control);
    setLoading(true);

    try {
      const zip = new JSZip();
      const tasks = files.map((file, idx) => {
        return fetch(file.url, { signal: control?.signal })
          .then((res) => {
            if (!res.ok) {
              throw new Error(`HTTP error! status: ${res.status}`);
            }
            return res.blob();
          })
          .then((blob) => {
            zip.file(files[idx].name || path.basename(file.url), blob, { binary: true });
          });
      });

      await Promise.all(tasks);
      const body = await zip.generateAsync({ type: 'blob' });
      let name = zipName;
      if (name) {
        if (!name.toLowerCase().endsWith('.zip')) {
          name += '.zip';
        }
      }
      saveAs(body, name || `download-${new Date().getTime()}.zip`);

      if (onSuccess) {
        onSuccess();
      }
      setLoading(false);
    } catch (err) {
      abort();
      setLoading(false);

      if (onError) {
        onError(err);
      }
    }
  };

  const cancel = () => {
    abort();
    setLoading(false);

    if (onCancel) {
      onCancel();
    }
  };

  const content = loading ? (
    <Space>
      <Button {...rests}>
        <LoadingOutlined />
        <span>下载中，请稍候..</span>
      </Button>
      <a onClick={cancel}>取消</a>
    </Space>
  ) : (
    <Tooltip title="文件选择过多，可能导致下载缓慢！" mouseLeaveDelay={2} open={visibleTips}>
      <Button {...rests} onClick={handleDownLoad}>
        <DownloadOutlined />
        {children}
      </Button>
    </Tooltip>
  );

  return <>{content}</>;
};

export default DownZipButton;
